#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include "LogMessage.hpp"
#include <jsoncpp/json/json.h>

using namespace std;

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

#define RECV_MAX 4096
#define SEP " "
#define SEP_LEN strlen(SEP)
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)


//ps:序列化和反序列只是便于结构化数据的传输
//我们仍然无法确保能够读到一个完整的数据报文
//因此我们需要制定协议来确保读到的是一个完整的数据报文

//协议内容为：x op y -> content_len\r\nx op y\r\n
//exitcode result -> content_len\r\nexitcode result\r\n
string enLength(const string &text)
{
    string content = to_string(text.size());
    content += LINE_SEP;
    content += text;
    content += LINE_SEP;
    return content;
}

bool deLength(string& recv_page, string *text)
{
    auto pos = recv_page.find(LINE_SEP);
    if (pos == string::npos) return false;

    string text_num = recv_page.substr(0, pos);
    int text_len = stoi(text_num);
    *text = recv_page.substr(pos+LINE_SEP_LEN, text_len);
    return true;
}

// 序列化格式：x op y -> 字符流
// 反序列格式：字符流 -> x op p

class request
{
public:
    request()
        : _x(0), _y(0), _op(0) {}

    request(int x, int y, char op)
        : _x(x), _y(y), _op(op) {}


    bool serializa(std::string *out)
    {
        out->clear();
#ifdef MYSELF
        *out += to_string(_x);
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += to_string(_y);
#else
        Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["operator"] = _op;

        Json::FastWriter writer;
        *out = writer.write(root);

#endif
        return true;
    }

    bool deserializa(std::string &inbuff)
    {
#ifdef MYSELF
        auto left_pos = inbuff.find(SEP);
        auto right_pos = inbuff.rfind(SEP);
        if (left_pos == string::npos || right_pos == string::npos)
            return false;
        if (left_pos == right_pos)
            return false;

        string x = inbuff.substr(0, left_pos);
        _op = inbuff[left_pos + SEP_LEN];
        string y = inbuff.substr(right_pos + SEP_LEN);

        if (x.empty() || y.empty())
            return false;

        _x = stoi(x);
        _y = stoi(y);
#else
        Json::Value root;
        Json::Reader read;
        read.parse(inbuff, root);
        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["operator"].asInt();
#endif
        return true;
    }

    int _x;
    int _y;
    char _op;
};


// 序列化格式：exitcode result -> 字符流
// 反序列格式：字符流 -> exitcode result
class response
{
public:
    response():_exitcode(-1), _result(-1){}
    response(int re_code, int result)
    :_exitcode(re_code), _result(result){}

    bool serializa(string *out)
    {
        out->clear();
#ifdef MYSELF
        *out += to_string(_exitcode);
        *out += SEP;
        *out += to_string(_result);
#else   
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _result;

        Json::FastWriter writer;
        *out = writer.write(root);
#endif
        return true;
    }

    bool deserializa(string &inbuff)
    {
#ifdef MYSELF
        auto mid = inbuff.find(SEP);
        if (mid == string::npos)
            return false;

        string exitcode = inbuff.substr(0, mid);
        string result = inbuff.substr(mid+SEP_LEN);

        if (exitcode.empty() || result.empty())
            return false;      
        
        _exitcode = stoi(exitcode);
        _result = stoi(result);
#else
        Json::Value root;
        Json::Reader read;
        read.parse(inbuff, root);
        _exitcode = root["exitcode"].asInt();
        _result = root["result"].asInt();
#endif
        return true;
    }

    int _exitcode;
    int _result;
};

bool RecvPackage(int sockfd, std::string &inbuff, std::string *text)
{
    char recv_buff[RECV_MAX] = {0};
    ssize_t size = recv(sockfd, recv_buff, sizeof recv_buff - 1, 0);
    if (size > 0)
    {
        recv_buff[size] = 0;
        inbuff += recv_buff;
        auto pos = inbuff.find(LINE_SEP);
        if (pos == string::npos) return false;

        string content_len = inbuff.substr(0, pos);
        int text_len = stoi(content_len);
        int total_len = content_len.size() + 2 * LINE_SEP_LEN + text_len;

        if (inbuff.size() < total_len)
        {
            logMessage(WARING, "get client message error");
            return false;
        }

        *text = inbuff.substr(0, total_len);
        //cout << "这里判断有没有从服务端收到消息：" << *text << endl;
        inbuff.erase(0, total_len);
        return true;
    }
    else
        return false;
}
